home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / disks / disk430.lzh / SmartFields / Docs / Create Program < prev    next >
Text File  |  1991-01-11  |  15KB  |  374 lines

  1. CREATING A SMARTFIELDS PROGRAM
  2.  
  3.  
  4. The following section describes the basic items you need to incorporate into
  5. your programs to use SmartFields.  The code segments were taken from the e.c
  6. example program.  You may wish to print a copy of the source code to follow
  7. along.
  8.  
  9.  
  10.     #include <console/console.h>
  11.     #include <console/fields.h>
  12.     #include <console/functions.h>
  13.  
  14. You will most likely need the first two include files in all of your
  15. programs.  The console/functions.h file was provided for your convenience so
  16. that you do not have to redeclare the SmartFields functions throughout your
  17. program.
  18.  
  19.     struct IntuitionBase *IntuitionBase = NULL;
  20.     struct GfxBase       *GfxBase = NULL;
  21.     struct Window        *win = NULL;
  22.     struct RastPort      *rp;
  23.  
  24. You need to open both the intuition.library and the graphics.library, as well
  25. as your own window.  The method above uses the library and window pointers
  26. themselves as flags indicating whether they have been opened.  By initially
  27. setting them to NULL, the end_program() function can detect whether it needs
  28. to close them.
  29.  
  30.     #define STRING_TEXT 1,0,JAM1,-3,-11,NULL
  31.     struct IntuiText name_text = { STRING_TEXT, (STRPTR)"Name", NULL };
  32.  
  33. A quick word on structure initialization:  We feel that pre-initializing
  34. Intuition (and SmartFields) structures is not only easier, but quicker and
  35. clearer than dynamically initializing them.  The exception to this, of
  36. course, is when you have multiple identical or nearly identical structures.
  37.  
  38. Pre-initialize IntuiText structures to hold your field titles.  The above
  39. settings are recommended as shown in the "Field Layout" section of this
  40. manual.
  41.  
  42.     SHORT name_pairs2[] = { 2,11, 274,11, 274, 1, 275, 1, 275,11 };
  43.     SHORT name_pairs1[] = { 0, 0, 273, 0, 273,10,   0,10,   0, 0 };
  44.  
  45.     #define BORDER2 -3,-2,2,0,JAM1,5
  46.     #define BORDER1 -3,-2,1,0,JAM1,5
  47.     struct Border name_border2 = { BORDER1, name_pairs1, NULL };
  48.     struct Border name_border1 = { BORDER2, name_pairs2, &name_border2 };
  49.  
  50. Pre-initialize your border pairs and Border structures.  The above method
  51. creates a white-line border around the field with a thin black "shadow"
  52. background.
  53.  
  54. Also initialize any Image structures which you may have.  Remember that
  55. graphics data must reside in CHIP RAM to be displayed properly.
  56.  
  57.     #define NAME_SIZE 30
  58.     UBYTE name_input[NAME_SIZE];
  59.     UBYTE name_undo[NAME_SIZE];
  60.     UBYTE name_dup[NAME_SIZE];
  61.  
  62. Define your Buffer, UndoBuffer, and DupBuffer for each field to be at least
  63. MaxChars large.  Remember that an UndoBuffer and a DupBuffer are not
  64. required, but are nice for users.
  65.  
  66.     #define NAME_FIELD 1
  67.  
  68. Create meaningful FieldID definitions for field identification throughout
  69. your program.  This parameter is especially handy in switch statements where
  70. you cannot check for field addresses.
  71.  
  72.     struct FieldMask phon_mask = MASK_ENTIRE_DISABLED;
  73.  
  74. Define any masks and set them equal to either MASK_ENTIRE_DISABLED or
  75. MASK_ENTIRE_ENABLED as defined in console/fields.h.  Remember, a C program
  76. does not automatically set variables to zero upon execution.
  77.  
  78.     #define FIRST_FIELD name_field
  79.     struct Field name_field = {
  80.       NULL, LATER, name_input, name_undo, name_dup, 1, 0,
  81.       CON_PLAIN, FIELD_ENABLED, NULL, NULL, LEFT_EDGE, 28,
  82.       0, 0, NAME_SIZE, 0, 0, 0, 0, &name_text, &name_border1,
  83.       NULL, NAME_FIELD, NULL, NULL, NULL
  84.     };
  85.     ...
  86.     struct Field numb_field = {
  87.       &phon_field, NULL, numb_input, numb_undo, numb_dup, 1, 0,
  88.       CON_PLAIN, FIELD_ENABLED, &numb_mask, NULL, RIGHT_EDGE, 138,
  89.       0, 0, NUMBER_SIZE, 0, 0, 0, 0, &numb_text, &numb_border1,
  90.       NULL, NUMB_FIELD, NULL, NULL, NULL
  91.     };
  92.     #define FINAL_FIELD numb_field
  93.  
  94. Initialize your Field structures.  Note that the PrevField pointer for the
  95. first field and the NextField pointer for the final field are set to NULL
  96. because they are at each end of the list.  Also notice that the PrevField
  97. pointers are set to the previous field listed, but the NextField pointer is
  98. set to the value LATER (NULL) as defined in toolkit/toolkit.h.  This is
  99. because the field_link() function (called by the field_open() function) sets
  100. these links.  The FIRST_FIELD and FINAL_FIELD definitions are not necessary,
  101. but are often convenient.
  102.  
  103.     struct FieldHeader field_header = { INIT_FIELD_HEADER };
  104.  
  105. Define a FieldHeader structure to be used for the field list in your window
  106. and initialize it using the INIT_FIELD_HEADER definition.  This sets all
  107. pointers to NULL to indicate that none of the required devices have been
  108. opened yet (which is important in case your program terminates prematurely).
  109.  
  110.     #define CURRENT_FIELD field_header.CurrentField
  111.  
  112. This definition is not required but often helpful.
  113.  
  114.     UBYTE con_buffer[CONSOLE_BUFFER_SIZE];
  115.  
  116. Define the console buffer (which is used to store console input) to be at
  117. least as large as CONSOLE_BUFFER_SIZE as defined in console/console.h.  A
  118. pointer to this buffer is stored in the FieldHeader structure by the
  119. field_open() function.
  120.  
  121.     struct NewWindow new_window = {
  122.       0, 0, 430, 200, 0, 1, CLOSEWINDOW | MENUPICK |
  123.       MOUSEBUTTONS | REFRESHWINDOW, ACTIVATE | SMART_REFRESH |
  124.       WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG | WINDOWSIZING,
  125.       NULL, NULL, (STRPTR)"SmartFields Example Program v1.0",
  126.       NULL, NULL, 50, 25, 430, 200, WBENCHSCREEN
  127.     };
  128.  
  129. The only item in the NewWindow structure required by SmartFields is the
  130. MOUSEBUTTONS flag in the IDCMPFlags parameter.  This lets Intuition know that
  131. you want to be notified each time the user clicks a mouse button so that the
  132. field_click() function can determine if the mouse was clicked in a field.  In
  133. most cases, you will also want the REFRESHWINDOW flag to notify you when you
  134. need to refresh the field display.
  135.  
  136.     #define WAIT_FOR_INPUT Wait(1L<<field_header.ReadPort->mp_SigBit|\
  137.                            1L<<win->UserPort->mp_SigBit)
  138.     #define CONSOLE_INPUT  message=(struct Message *)\
  139.                            GetMsg(field_header.ReadPort)
  140.     #define WINDOW_INPUT   imessage=(struct IntuiMessage *)\
  141.                            GetMsg(win->UserPort)
  142.  
  143. These definitions make your Amiga C program seem just a little bit less
  144. cryptic.
  145.  
  146.     main()
  147.     {
  148.       open_all();
  149.       initialize();
  150.       get_inputs();
  151.     }
  152.  
  153. Just a personal opinion here: keep your main() segment short and sweet.
  154.  
  155.     draw_screen()
  156.     {
  157.       field_refresh( &field_header, &FIRST_FIELD, -1, CURRENT_FIELD );
  158.     }
  159.  
  160. This function was set up to be called 1) when the window is first displayed,
  161. and 2) each time the window needs refreshing.  The field_refresh() function
  162. draws each field's title, border, imagery, and contents.  This also moves the
  163. cursor to the first field because CURRENT_FIELD is initially set to point to
  164. the first field by the field_open() function.
  165.  
  166.     end_program( return_code )
  167.       int return_code;
  168.     {
  169.       field_close( &field_header );
  170.       if (win)           { ClearMenuStrip( win ); CloseWindow( win );
  171.     }
  172.       if (GfxBase)         CloseLibrary( GfxBase );
  173.       if (IntuitionBase)   CloseLibrary( IntuitionBase );
  174.       exit( return_code );
  175.     }
  176.  
  177. Another programming hint: have a single program-ending function, and use the
  178. window/device/library pointers themselves as flags.  If there was the
  179. possibility that this end_program() function might be executed more than once
  180. during the program (for example, if this program is actually a sub-program of
  181. a larger program), you would need to reset the pointers (win, GfxBase,
  182. IntuitionBase) back to NULL after you closed their corresponding devices.
  183.  
  184. The field_close() function closes the console and other required devices that
  185. were opened by the field_open() function.  This must occur BEFORE the window
  186. is closed, otherwise the program may crash.
  187.  
  188. Notice the libraries are closed only if they were opened.  All good
  189. programmers clean up after themselves.  Also, using the exit() function to
  190. pass a return code back to the CLI is a good debugging method.
  191.  
  192.     get_inputs()
  193.     {
  194.       struct  IntuiMessage *imessage;
  195.       ULONG   key;
  196.       struct  Message *message;
  197.       struct  Field *where;
  198.  
  199. Although this is not perfectly structured programming, it is easier to make
  200. the get_inputs() function a forever-loop and call the end_program() function
  201. when the user clicks the close gadget.  The imessage variable is used to
  202. point to Intuition messages, and the message variable is used to point to
  203. console messages.
  204.  
  205.     FOREVER {
  206.       WAIT_FOR_INPUT;
  207.  
  208. This is NOT a busy wait.  The task sleeps until the user presses a key or
  209. clicks the mouse while the window is active.
  210.  
  211.     if (CONSOLE_INPUT) {
  212.       key = field_input( &field_header );
  213.       switch (key) {
  214.         case FIELD_SWALLOW:  break;
  215.         case FIELD_RETURN:
  216.         case FIELD_NEXT:     next_field(); break;
  217.         case FIELD_PREVIOUS: previous_field(); break;
  218.         case FIELD_FIRST:
  219.           if (working_ven)
  220.             field_goto( &field_header, &add1_field );
  221.           break;
  222.         case FIELD_FINAL:
  223.           if (working_ven)
  224.             field_goto( &field_header, &FINAL_FIELD );
  225.           break;
  226.       } /* switch key */
  227.     }   /* if keyboard input */
  228.  
  229. Note that there are only a few possible codes returned by the field_input()
  230. function (listed in console/fields.h).  Because the field_input() function
  231. handles most of the necessary commands, the most common return code will be
  232. FIELD_SWALLOW, and therefore this should be at the top of the list.  Notice
  233. that it is up to you to decide what you want to do when the user presses one
  234. of the function, control, or cursor keys (ignoring the control keys used by
  235. SmartFields).
  236.  
  237.     while (WINDOW_INPUT) {
  238.       switch (imessage->Class) {
  239.  
  240. You need to use a while() statement when checking for Intuition messages, for
  241. they may be queued up.
  242.  
  243.     case MOUSEBUTTONS:
  244.       if (imessage->Code == LEFT_MOUSE_BUTTON)
  245.         if (where = field_click( &field_header,
  246.                     imessage->MouseX, imessage->MouseY ))
  247.           if (working_ven ||
  248.             (!working_ven && where->FieldID == NAME_FIELD)) {
  249.             where->BufferPos = field_header.BufferPos;
  250.             field_goto( &field_header, where );
  251.           }
  252.       break;
  253.  
  254. Since a mouse click is the most common input event, this should be the first
  255. case after the switch() statement.  Note that you must also check for the
  256. LEFT_MOUSE_BUTTON code because a MOUSEBUTTONS event is generated for both
  257. left and right mouse button clicks.
  258.  
  259. If you are interested in which field the mouse was clicked, call the
  260. field_click() function.  It will return to you a pointer to the field in
  261. which the mouse was clicked or NULL if it was not clicked in any field.
  262. Notice that it is up to you whether the cursor should actually move to that
  263. field.  If you do, you need to set the BufferPos parameter of the field to
  264. which you are moving equal to the BufferPos in which the mouse was clicked
  265. (returned in the FieldHeader structure by the field_click() function).  Then
  266. you need to call the field_goto() function to move the cursor to that field.
  267.  
  268.     case REFRESHWINDOW:
  269.       draw_screen();
  270.       BeginRefresh( win );
  271.       EndRefresh( win, TRUE );
  272.       break;
  273.  
  274. As mentioned earlier, you can create a single function to not only draw in
  275. the window initially, but also when it needs refreshing.  Note that if this
  276. function contains any console function (the draw_screen() function contains
  277. the field_refresh() function), it must be called BEFORE the BeginRefresh()/
  278. EndRefresh() pair, because the BeginRefresh() function locks the layers the
  279. console device uses to render to cursor.  If you place it between the pair,
  280. the cursor may partially or completely disappear.
  281.  
  282.     case CLOSEWINDOW:
  283.       end_program( 0 );
  284.       break;
  285.  
  286. This is how you break out of the forever-loop.
  287.  
  288.     ReplyMsg( imessage );
  289.  
  290. Don't forget to respond to your Intuition messages so the system doesn't get
  291. bogged down.  The field_input() function automatically responds to the
  292. console messages.
  293.  
  294.     initialize()
  295.     {
  296.       mask_chars( &phon_mask, "0123456789()-/ ", MASK_ENABLE );
  297.       mask_range( &numb_mask, '0', '9', MASK_ENABLE );
  298.       draw_screen();
  299.     }
  300.  
  301. You will want to initialize your masks before rendering the fields, however
  302. you may change the masks at any time.  Notice the initial call to the
  303. draw_screen() function.
  304.  
  305.     open_all()
  306.     {
  307.       int error;
  308.  
  309.       if (!(IntuitionBase = (struct IntuitionBase *)
  310.             OpenLibrary( "intuition.library", LIBRARY_VERSION )))
  311.         end_program( 0x0100 );
  312.       if (!(GfxBase = (struct GfxBase *)
  313.             OpenLibrary( "graphics.library", 0L )))
  314.         end_program( 0x0101 );
  315.  
  316.      if (!(win = OpenWindow( &new_window )))
  317.         end_program( 0x0102 );
  318.       rp = win->RPort;
  319.  
  320.       if (error = field_open( win, &field_header, &FIRST_FIELD,
  321.                               &FINAL_FIELD, con_buffer ))
  322.         end_program( error );
  323.     }
  324.  
  325. This is where you need to open the required libraries, windows, and devices.
  326. Notice that if any of these fail to open, the end_program() function is
  327. called immediately and sent a return code for debugging purposes.  The
  328. field_open() function opens the console and other devices required for
  329. SmartFields operation.  Notice the FIRST_FIELD and LAST_FIELD definitions.
  330. The FIRST_FIELD is made current by this function.
  331.  
  332.     field_clear( &field_header, &FIRST_FIELD, -1, &FIRST_FIELD );
  333.  
  334. This line is contained in the new_vendor() function of the e.c source code.
  335. It is used to clear all of the fields when 1) the user has decided to start
  336. over, or 2) the user has successfully entered a vendor record.
  337.  
  338.     previous_field()
  339.     {
  340.       if (CURRENT_FIELD->FieldID == CONT_FIELD) {
  341.              if (add4_input[0]) field_goto( &field_header, &add4_field );
  342.         else if (add3_input[0]) field_goto( &field_header, &add3_field );
  343.         else if (add2_input[0]) field_goto( &field_header, &add2_field );
  344.         else                    field_goto( &field_header, &add1_field );
  345.       }
  346.       ...
  347.  
  348. Notice how tricky you can get with the cursor movements.
  349.  
  350.     field_redisplay( &field_header, &add1_field, -1 );
  351.  
  352. This function was called when a vendor record was being changed, and all of
  353. the fields needed to be redisplayed with the contents of the record.
  354.  
  355.     vendor_number()
  356.     {
  357.       int number, atoi();
  358.       number = atoi( numb_input );
  359.       sprintf( numb_input, "%04d", number );
  360.       field_redisplay( &field_header, &numb_field, 1, &add1_field );
  361.     }
  362.  
  363. This is an example of how you can have formatted input fields.  Just change
  364. the contents of the Buffer to how you want it (as long as the length of the
  365. Buffer including the terminal null is still less than MaxChars) and call the
  366. field_redisplay() function to redisplay the field with its new contents.
  367.  
  368.  
  369. Create Program  01/13/90
  370. © Copyright 1990 Timm Martin
  371. All Rights Reserved Worldwide
  372.  
  373. /*-- END --*/
  374.